package com.easily.factory.aop;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ProxyHelp {

    /**
     * 生成代理对象
     * @param targetProxyClass 接口class或目标对象class
     * @param targetObject 目标对象
     * @param aopObject aop对象
     * @param <T>
     * @return 返回代理对象
     */
    public <T> T getProxy(Class<T> targetProxyClass,Object targetObject,Object aopObject,boolean isAllMethodProxy){
        AopObject aop = new AopObject(aopObject);
        ProxyObject proxyObject = targetProxyClass == targetObject.getClass() ? new CGlibProxy(targetObject, aop,isAllMethodProxy):new JDKProxy(targetObject, aop,isAllMethodProxy);
        return proxyObject.getProxy(targetProxyClass);
    }

    /**
     * 是否匹配整个类
     * @param aopValue aop注解上的value
     * @param targetName 目标类名
     * @return 是否匹配整个类
     */
    public boolean isAopClass(String aopValue,String targetName){
        Pattern pattern = Pattern.compile(aopValue);
        Matcher matcher = pattern.matcher(targetName);
        return matcher.matches();
    }

    /**
     * 匹配目标类中的某个方法
     * @param aopValue aop注解上的value
     * @param targetObject 目标类名
     * @return 匹配目标类中的某个方法
     */
    public boolean haveAopMethod(String aopValue,Object targetObject){
        String targetName = targetObject.getClass().getName()+".";
        Pattern pattern = Pattern.compile(aopValue);
        for (Method method : targetObject.getClass().getDeclaredMethods()) {
            Matcher matcher = pattern.matcher(targetName+method.getName());
            if (matcher.matches()){
                return true;
            }
        }
        return false;
    }

    // 获取代理后的对象
    public <T> T toProxy(Class<T> targetProxyClass,Object targetObject,Map<String[],Object> aopMp){
        String targetName = targetObject.getClass().getName();

        T proxy;
        try {
            proxy = targetProxyClass.cast(targetObject);
        }catch (Exception e){
            // targetObject不能强转为 T，证明 T 不是targetObject的接口或类型
            return null;
        }

        // 外层循环：循环匹配所有的aop类
        out:for (Map.Entry<String[],Object> entry : aopMp.entrySet()) {
            String[] aopValues = entry.getKey();
            boolean haveAopMethod = false;

            // 内层循环：循环一个aop类的所有匹配规则
            for (String aopValue:aopValues){
                // 检查是不是 class/package 开头的aopValue
                if(aopValue.startsWith("class:") || aopValue.startsWith("package:")){
                    // 匹配类
                    aopValue = aopValue.split(":")[1];
                    if(isAopClass(aopValue,targetName)){
                        proxy = getProxy(targetProxyClass, targetObject, entry.getValue(),true);
                        continue out;
                    }else continue;
                }else if(aopValue.endsWith(".*")){
                    // 以 .* 结尾的默认按照匹配整个类进行处理
                    if(isAopClass(aopValue,targetName)){
                        proxy = getProxy(targetProxyClass, targetObject, entry.getValue(),true);
                        continue out;
                    }
                    // 匹配整个类失败，继续按照方法匹配
                }

                // 匹配方法
                if(aopValue.startsWith("method:")) aopValue = aopValue.replace("method:","");
                if (haveAopMethod(aopValue,targetObject)){
                    haveAopMethod = true;
                }

            }
            if(haveAopMethod){
                proxy = getProxy(targetProxyClass,targetObject,entry.getValue(),false);
            }
        }
        return proxy;
    }
}
